package Servicios;

import DAO.DAOAsignaturaOfertaAcademica;
import DAO.DAOAsignaturaOptativa;
import DAO.DAOAsignaturasAlumno;
import DAO.DAOAsignaturasOptativasAlumno;
import DAO.DAOInformacionAlumno;
import DAO.DAOOfertaAcademica;
import DAO.DAOProgramaEducativo;
import DAO.DAORelacionAlumnoProgramaEducativo;
import DAO.DAORequerimientoAcademico;
import Dominio.Asignatura;
import Dominio.AsignaturaOfertaAcademica;
import Dominio.AsignaturaOfertaAcademicaPonderada;
import Dominio.FragmentoHorario;
import Dominio.AsignaturaImpartidaDia;
import Dominio.OfertaAcademica;
import Dominio.OpcionHorario;
import Dominio.RequerimientoAcademico;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Date;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class GestorGeneradorHorarios extends HttpServlet {

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();

        HttpSession sesion = request.getSession();
        String nombreUsuario = sesion.getAttribute("nombreUsuario").toString();
        ArrayList<AsignaturaOfertaAcademicaPonderada> arregloAsignaturas = (ArrayList<AsignaturaOfertaAcademicaPonderada>) sesion.getAttribute("asignaturas");

        String numeroMaterias = request.getParameter("numeroMaterias");


        if (nombreUsuario != null && numeroMaterias != null) {

            int numeroDeAsignaturas = Integer.parseInt(numeroMaterias);
            
            int claveInformacionAlumno = obtenerClaveInformacionAlumno(nombreUsuario);                       
            int clavePE = obtenerClavePE(claveInformacionAlumno);
            String abreviaturaPE = obtenerAbreviaturaPE(clavePE);           
           
            
            DAORelacionAlumnoProgramaEducativo daoRelacionAlumnoPE = new DAORelacionAlumnoProgramaEducativo();            
            int claveRelacionAlumnoPE = daoRelacionAlumnoPE.obtenerClaveRelacionAlumnoPE(claveInformacionAlumno);
            daoRelacionAlumnoPE.cerrarConexionARelacionAlumnoProgramaEducativo();
            
            int numeroDeAsignaturasAlumno = 0;
            DAOAsignaturasAlumno daoAsignaturasAlumno = new DAOAsignaturasAlumno();
            numeroDeAsignaturasAlumno += daoAsignaturasAlumno.obtenerNumeroDeAsignaturasDelAlumno(claveRelacionAlumnoPE);
            daoAsignaturasAlumno.cerrarConexionAAsignaturaAlumno();
            
            DAOAsignaturasOptativasAlumno daoAsignaturasOptativasAlumno = new DAOAsignaturasOptativasAlumno();
            numeroDeAsignaturasAlumno += daoAsignaturasOptativasAlumno.obtenerNumeroDeAsignaturasOptativasDelAlumno(claveRelacionAlumnoPE);
            daoAsignaturasOptativasAlumno.cerrarConexionAAsignaturaOptativaAlumno();
            
            if(numeroDeAsignaturasAlumno > 0) {
                                                
                    if (arregloAsignaturas == null) {
                        ArrayList<AsignaturaOfertaAcademica> listaAsignaturasOfertadas = obtenerAsignaturasOfertadas(abreviaturaPE);            
                        
                        if(listaAsignaturasOfertadas.size() > 0) {
                        
                            arregloAsignaturas = generarAsignaturasPonderadas(request, response, listaAsignaturasOfertadas, claveInformacionAlumno, clavePE);
                            ArrayList<OpcionHorario> opcionesDeHorario = obtenerOpcionesDeHorario(arregloAsignaturas, numeroDeAsignaturas);

                            imprimirOpcionesDeHorario(opcionesDeHorario, out);
                        } 
                        else {
                            String respuesta = "<h1>En estos momentos no existe una oferta académica en el sistema, por lo que no puede generar sus opciones de horarios</h1>";
                            out.println(respuesta);
                        }

                    } else {
                        ArrayList<OpcionHorario> opcionesDeHorario = obtenerOpcionesDeHorario(arregloAsignaturas, numeroDeAsignaturas);

                        imprimirOpcionesDeHorario(opcionesDeHorario, out);

                    }                
            }
            else {
                String respuesta = "<h1>Para generar sus opciones de horario debe gestionar antes el estado de sus asignaturas</h1>";
                out.println(respuesta);
            }
        } else {
            String respuesta = "Ocurrio un error al tratar de generar las opciones de horarios";
            out.println(respuesta);
        }
    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /**
     * Handles the HTTP
     * <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP
     * <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>

    private ArrayList<AsignaturaOfertaAcademicaPonderada> generarAsignaturasPonderadas(HttpServletRequest request, HttpServletResponse response, ArrayList<AsignaturaOfertaAcademica> listaAsignaturasOfertadas, int claveInformacionAlumno, int clavePE) {        
        
        System.out.println("Obteniendo asignaturas normales aprobadas");
        ArrayList<AsignaturaOfertaAcademica> listaAsignaturasNormalesAprobadas = obtenerAsignaturasNormalesPorEstadoOfertada(listaAsignaturasOfertadas, /*claveOfertaAcademica,*/ claveInformacionAlumno, clavePE, ESTADO_APROBADA);
        //ArrayList<AsignaturaOfertaAcademica> listaAsignaturasNormalesNoCursables = obtenerAsignaturasNormalesPorEstadoOfertada(claveOfertaAcademica, claveInformacionAlumno, clavePE, ESTADO_NO_CURSABLE);
        System.out.println("Obteniendo asignaturas normales recursables");
        ArrayList<AsignaturaOfertaAcademica> listaAsignaturasNormalesRecursables = obtenerAsignaturasNormalesPorEstadoOfertada(listaAsignaturasOfertadas, /*claveOfertaAcademica,*/ claveInformacionAlumno, clavePE, ESTADO_RECURSABLE);
        System.out.println("Obteniendo asignaturas normales cursables sin recursables");
        ArrayList<AsignaturaOfertaAcademica> listaAsignaturasNormalesCursablesSinRecursables = obtenerAsignaturasNormalesPorEstadoOfertada(listaAsignaturasOfertadas, /*claveOfertaAcademica,*/ claveInformacionAlumno, clavePE, ESTADO_CURSABLE_SIN_RECURSABLE);

        System.out.println("Obteniendo asignaturas optativas aprobadas");
        ArrayList<AsignaturaOfertaAcademica> listaAsignaturasOptativasAprobadas = obtenerAsignaturasOptativasPorEstadoOfertada(listaAsignaturasOfertadas, /*claveOfertaAcademica,*/ claveInformacionAlumno, clavePE, ESTADO_APROBADA);
        //ArrayList<AsignaturaOfertaAcademica> listaAsignaturasOptativasNoCursables = obtenerAsignaturasOptativasPorEstadoOfertada(claveOfertaAcademica, claveInformacionAlumno, clavePE, ESTADO_NO_CURSABLE);
        System.out.println("Obteniendo asignaturas optativas recursables");
        ArrayList<AsignaturaOfertaAcademica> listaAsignaturasOptativasRecursables = obtenerAsignaturasOptativasPorEstadoOfertada(listaAsignaturasOfertadas, /*claveOfertaAcademica,*/ claveInformacionAlumno, clavePE, ESTADO_RECURSABLE);
        System.out.println("Obteniendo asignaturas optativas cursables sin recursables");
        ArrayList<AsignaturaOfertaAcademica> listaAsignaturasOptativasCursablesSinRecursables = obtenerAsignaturasOptativasPorEstadoOfertada(listaAsignaturasOfertadas, /*claveOfertaAcademica,*/ claveInformacionAlumno, clavePE, ESTADO_CURSABLE_SIN_RECURSABLE);

        ArrayList<AsignaturaOfertaAcademicaPonderada> arregloAsignaturasOrdenadas = new ArrayList<AsignaturaOfertaAcademicaPonderada>();

        if (obtenerNumeroDeAsignaturasOptativasAprobadas(listaAsignaturasOptativasAprobadas) < 6) {

            System.out.println("Obteniendo todas las asignaturas aprobadas");
            ArrayList<AsignaturaOfertaAcademica> listaDeTodasLasAsignaturasAprobadas = obtenerTodasLasAsignaturasAprobadas(listaAsignaturasNormalesAprobadas, listaAsignaturasOptativasAprobadas);

            System.out.println("Obteniendo ponderaciones de asignaturas normales recursables");
            ArrayList<AsignaturaOfertaAcademicaPonderada> listaAsignaturasPonderadasNormalesRecursables = obtenerAsignaturasPonderadasRecursables(listaAsignaturasNormalesRecursables);
            System.out.println("Obteniendo ponderaciones de asignaturas cursables sin recursables");
            ArrayList<AsignaturaOfertaAcademicaPonderada> listaAsignaturasPonderadasNormalesCursablesSinRecursables = obtenerAsignaturasPonderadasNormales(listaAsignaturasNormalesCursablesSinRecursables);
            System.out.println("Obteniendo ponderaciones de asignaturas optativas recursables");
            ArrayList<AsignaturaOfertaAcademicaPonderada> listaAsignaturasPonderadasOptativasRecursables = obtenerAsignaturasPonderadasOptativas(listaAsignaturasOptativasRecursables);
            System.out.println("Obteniendo ponderaciones de asignaturas optativas cursables sin recursables");
            ArrayList<AsignaturaOfertaAcademicaPonderada> listaAsignaturasPonderadasOptativasCursablesSinRecursables = obtenerAsignaturasPonderadasOptativas(listaAsignaturasOptativasCursablesSinRecursables);

            System.out.println("Asignar ponderacion con base en semestre de asignaturas normales recursables");
            asignarPonderacionAAsignaturasPorSemestre(listaAsignaturasPonderadasNormalesRecursables);
            System.out.println("Asignar ponderacion con base en semestre de asignaturas normales cursables sin recursables");
            asignarPonderacionAAsignaturasPorSemestre(listaAsignaturasPonderadasNormalesCursablesSinRecursables);
            System.out.println("Asignar ponderacion con base en semestre de asignaturas optativas recursables");
            asignarPonderacionAAsignaturasPorSemestre(listaAsignaturasPonderadasOptativasRecursables);
            System.out.println("Asignar ponderacion con base en semestre de asignaturas optativas cursables sin recursables");
            asignarPonderacionAAsignaturasPorSemestre(listaAsignaturasPonderadasOptativasCursablesSinRecursables);

            System.out.println("Asignar ponderacion con base en requerimientos de asignaturas normales cursables sin recursables");
            asignarPonderacionesConBaseEnLosRequerimientosAcademicos(listaAsignaturasPonderadasNormalesCursablesSinRecursables, listaDeTodasLasAsignaturasAprobadas, clavePE);
            System.out.println("Asignar ponderacion con base en requerimientos de asignaturas optativas recursables");
            asignarPonderacionesConBaseEnLosRequerimientosAcademicos(listaAsignaturasPonderadasOptativasRecursables, listaDeTodasLasAsignaturasAprobadas, clavePE);
            System.out.println("Asignar ponderacion con base en requerimientos de asignaturas optativas cursables sin recursables");
            asignarPonderacionesConBaseEnLosRequerimientosAcademicos(listaAsignaturasPonderadasOptativasCursablesSinRecursables, listaDeTodasLasAsignaturasAprobadas, clavePE);

            System.out.println("Uniendo arreglos de asignaturas");
            arregloAsignaturasOrdenadas = unirArreglosDeAsignaturasPonderadas(listaAsignaturasPonderadasNormalesRecursables, listaAsignaturasPonderadasNormalesCursablesSinRecursables, listaAsignaturasPonderadasOptativasRecursables, listaAsignaturasPonderadasOptativasCursablesSinRecursables);
        } else {
            
            System.out.println("Obteniendo todas las asignaturas aprobadas");
            ArrayList<AsignaturaOfertaAcademica> listaDeTodasLasAsignaturasAprobadas = obtenerTodasLasAsignaturasAprobadas(listaAsignaturasNormalesAprobadas, listaAsignaturasOptativasAprobadas);

            System.out.println("Obteniendo ponderaciones de asignaturas normales recursables");
            ArrayList<AsignaturaOfertaAcademicaPonderada> listaAsignaturasPonderadasNormalesRecursables = obtenerAsignaturasPonderadasRecursables(listaAsignaturasNormalesRecursables);
            System.out.println("Obteniendo ponderaciones de asignaturas cursables sin recursables");
            ArrayList<AsignaturaOfertaAcademicaPonderada> listaAsignaturasPonderadasNormalesCursablesSinRecursables = obtenerAsignaturasPonderadasNormales(listaAsignaturasNormalesCursablesSinRecursables);

            System.out.println("Asignar ponderacion con base en semestre de asignaturas normales recursables");
            asignarPonderacionAAsignaturasPorSemestre(listaAsignaturasPonderadasNormalesRecursables);
            System.out.println("Asignar ponderacion con base en semestre de asignaturas normales cursables sin recursables");
            asignarPonderacionAAsignaturasPorSemestre(listaAsignaturasPonderadasNormalesCursablesSinRecursables);

            System.out.println("Asignar ponderacion con base en requerimientos de asignaturas normales cursables sin recursables");
            asignarPonderacionesConBaseEnLosRequerimientosAcademicos(listaAsignaturasPonderadasNormalesCursablesSinRecursables, listaDeTodasLasAsignaturasAprobadas, clavePE);

            System.out.println("Uniendo arreglos de asignaturas");
            arregloAsignaturasOrdenadas = unirArreglosDeAsignaturasPonderadas(listaAsignaturasPonderadasNormalesRecursables, listaAsignaturasPonderadasNormalesCursablesSinRecursables);
        }

        HttpSession sesion = request.getSession();
        sesion.setAttribute("asignaturas", arregloAsignaturasOrdenadas);

        return arregloAsignaturasOrdenadas;
    }

    private int obtenerClaveInformacionAlumno(String nombreUsuario) {
        int claveInformacionAlumno = 0;
        DAOInformacionAlumno daoInformacionAlumno = new DAOInformacionAlumno();
        claveInformacionAlumno = daoInformacionAlumno.obtenerClaveInfoAlumno(nombreUsuario);
        daoInformacionAlumno.cerrarConexionADAOInformacionAlumno();
        return claveInformacionAlumno;
    }

    private int obtenerClavePE(int claveInformacionAlumno) {
        int clavePE = 0;
        DAORelacionAlumnoProgramaEducativo daoRelacionAlumnoPE = new DAORelacionAlumnoProgramaEducativo();
        clavePE = daoRelacionAlumnoPE.obtenerClavePE(claveInformacionAlumno);
        daoRelacionAlumnoPE.cerrarConexionARelacionAlumnoProgramaEducativo();
        return clavePE;
    }
    
    public String obtenerAbreviaturaPE(int clavePE) {
        DAOProgramaEducativo daoPE = new DAOProgramaEducativo();
        String abreviaturaPE = daoPE.obtenerabreviaturaDePE(clavePE);
        daoPE.cerrarconexionAProgramas();
        
        return abreviaturaPE;
    }

    private ArrayList<AsignaturaOfertaAcademica> obtenerAsignaturasOfertadas(String abreviaturaProgramaEducativo) {
        DAOAsignaturaOfertaAcademica daoAsignaturaOfertaAcademica = new DAOAsignaturaOfertaAcademica();
        ArrayList<AsignaturaOfertaAcademica> listaAsignaturasOfertadas = daoAsignaturaOfertaAcademica.buscarAsignaturasOfertadasPorPE(abreviaturaProgramaEducativo);
        daoAsignaturaOfertaAcademica.cerrarConexionAAsignaturaOferta();
        
        return listaAsignaturasOfertadas;
    }

    private ArrayList<AsignaturaOfertaAcademica> obtenerAsignaturasNormalesPorEstadoOfertada(ArrayList<AsignaturaOfertaAcademica> asignaturasOfertadas, /*String claveOferta,*/ int claveInfoAlumno, int claveProgramaEducativo, int estado) {
        DAOAsignaturasAlumno daoAsignaturasAlumno = new DAOAsignaturasAlumno();
        ArrayList<AsignaturaOfertaAcademica> listaAsignaturasPorEstadoOfertada = daoAsignaturasAlumno.obtenerAsignaturasPorEstadoOfertada2(asignaturasOfertadas, /*claveOferta,*/ claveInfoAlumno, claveProgramaEducativo, estado);
        daoAsignaturasAlumno.cerrarConexionAAsignaturaAlumno();

        return listaAsignaturasPorEstadoOfertada;
    }

    private ArrayList<AsignaturaOfertaAcademica> obtenerAsignaturasOptativasPorEstadoOfertada(ArrayList<AsignaturaOfertaAcademica> asignaturasOfertadas, /*String claveOferta,*/ int claveInfoAlumno, int claveProgramaEducativo, int estado) {
        DAOAsignaturasOptativasAlumno daoAsignaturasOptativasAlumno = new DAOAsignaturasOptativasAlumno();
        ArrayList<AsignaturaOfertaAcademica> listaAsignaturasOptativasPorEstadoOfertada = daoAsignaturasOptativasAlumno.obtenerAsignaturasPorEstadoOfertada3(asignaturasOfertadas,/* claveOferta,*/ claveInfoAlumno, claveProgramaEducativo, estado);
        daoAsignaturasOptativasAlumno.cerrarConexionAAsignaturaOptativaAlumno();

        return listaAsignaturasOptativasPorEstadoOfertada;
    }

    private ArrayList<AsignaturaOfertaAcademica> obtenerTodasLasAsignaturasAprobadas(ArrayList<AsignaturaOfertaAcademica> listaAsignaturasNormalesAprobadas, ArrayList<AsignaturaOfertaAcademica> listaAsignaturasOptativasAprobadas) {
        ArrayList<AsignaturaOfertaAcademica> listaTodasLasAsignaturasAprobadas = new ArrayList<AsignaturaOfertaAcademica>();

        listaTodasLasAsignaturasAprobadas.addAll(listaAsignaturasNormalesAprobadas);
        listaTodasLasAsignaturasAprobadas.addAll(listaAsignaturasOptativasAprobadas);

        return listaTodasLasAsignaturasAprobadas;
    }

    private ArrayList<AsignaturaOfertaAcademicaPonderada> obtenerAsignaturasPonderadasRecursables(ArrayList<AsignaturaOfertaAcademica> listaAsignaturasRecursables) {
        ArrayList<AsignaturaOfertaAcademicaPonderada> listaAsignaturasRecursablesPonderadas = new ArrayList<AsignaturaOfertaAcademicaPonderada>();

        for (int i = 0; i < listaAsignaturasRecursables.size(); i++) {
            AsignaturaOfertaAcademica asignaturaOfertaAcademica = listaAsignaturasRecursables.get(i);
            AsignaturaOfertaAcademicaPonderada asignaturaPonderada = new AsignaturaOfertaAcademicaPonderada();
            asignaturaPonderada.setAsignaturaOferta(asignaturaOfertaAcademica);
            asignaturaPonderada.setPonderacion(PONDERACION_ASIGNATURA_RECURSABLE);
            listaAsignaturasRecursablesPonderadas.add(asignaturaPonderada);
        }

        return listaAsignaturasRecursablesPonderadas;
    }

    private ArrayList<AsignaturaOfertaAcademicaPonderada> obtenerAsignaturasPonderadasNormales(ArrayList<AsignaturaOfertaAcademica> listaAsignaturasNormales) {
        ArrayList<AsignaturaOfertaAcademicaPonderada> listaAsignaturasNormalesPonderadas = new ArrayList<AsignaturaOfertaAcademicaPonderada>();

        for (int i = 0; i < listaAsignaturasNormales.size(); i++) {
            AsignaturaOfertaAcademica asignaturaOfertaAcademica = listaAsignaturasNormales.get(i);
            AsignaturaOfertaAcademicaPonderada asignaturaPonderada = new AsignaturaOfertaAcademicaPonderada();
            asignaturaPonderada.setAsignaturaOferta(asignaturaOfertaAcademica);
            asignaturaPonderada.setPonderacion(PONDERACION_ASIGNATURA_NORMAL);
            listaAsignaturasNormalesPonderadas.add(asignaturaPonderada);
        }
        return listaAsignaturasNormalesPonderadas;
    }

    private ArrayList<AsignaturaOfertaAcademicaPonderada> obtenerAsignaturasPonderadasOptativas(ArrayList<AsignaturaOfertaAcademica> listaAsignaturasOptativas) {
        ArrayList<AsignaturaOfertaAcademicaPonderada> listaAsignaturasOptativasPonderadas = new ArrayList<AsignaturaOfertaAcademicaPonderada>();

        for (int i = 0; i < listaAsignaturasOptativas.size(); i++) {
            AsignaturaOfertaAcademica asignaturaOfertaAcademica = listaAsignaturasOptativas.get(i);
            AsignaturaOfertaAcademicaPonderada asignaturaPonderada = new AsignaturaOfertaAcademicaPonderada();
            asignaturaPonderada.setAsignaturaOferta(asignaturaOfertaAcademica);
            asignaturaPonderada.setPonderacion(PONDERACION_ASIGNATURA_OPTATIVA);
            listaAsignaturasOptativasPonderadas.add(asignaturaPonderada);
        }
        return listaAsignaturasOptativasPonderadas;
    }

    private void asignarPonderacionAAsignaturasPorSemestre(ArrayList<AsignaturaOfertaAcademicaPonderada> listaAsignaturasPonderadas) {

        for (int i = 0; i < listaAsignaturasPonderadas.size(); i++) {
            AsignaturaOfertaAcademicaPonderada asignatura = listaAsignaturasPonderadas.get(i);

            String semestre = asignatura.getAsignaturaOferta().getSemestre();
            int ponderacionPorSemestre = obtenerPonderacionPorSemestre(semestre);

            asignatura.sumarPonderacion(ponderacionPorSemestre);
        }

    }

    private int obtenerPonderacionPorSemestre(String semestre) {

        int ponderacionResultante = 0;

        if(semestre.equals("1")) {         
                ponderacionResultante = 8;
        }
        else if(semestre.equals("2")) {
                ponderacionResultante = 7;
        }
        else if(semestre.equals("3")){
                ponderacionResultante = 6;
        }
        else if(semestre.equals("4")){
                ponderacionResultante = 5;
        }
        else if(semestre.equals("5")){
                ponderacionResultante = 4;
        }
        else if(semestre.equals("6")){
                ponderacionResultante = 3;
        }
        else if(semestre.equals("7")){
                ponderacionResultante = 2;
        }
        else if(semestre.equals("8")){
                ponderacionResultante = 1;
        }        

        return ponderacionResultante;
    }

    private void asignarPonderacionesConBaseEnLosRequerimientosAcademicos(ArrayList<AsignaturaOfertaAcademicaPonderada> listaAsignaturasDependientes, ArrayList<AsignaturaOfertaAcademica> listaDeTodasLasAsignaturasAprobadas, int clavePE) {

        for (int i = 0; i < listaAsignaturasDependientes.size(); i++) {            

            AsignaturaOfertaAcademicaPonderada asignaturaDependiente = listaAsignaturasDependientes.get(i);
            int claveAsignatura = asignaturaDependiente.getAsignaturaOferta().getClaveAsignatura();

            DAORequerimientoAcademico daoRequerimientoAcademico = new DAORequerimientoAcademico();
            RequerimientoAcademico requerimientoAcademico = daoRequerimientoAcademico.obtenerRequerimientoAcademico(claveAsignatura, clavePE);
            
            if(requerimientoAcademico != null) {
                ArrayList<Asignatura> listaAsignaturasRequeridas = requerimientoAcademico.getAsignaturasRequeridas();

                for (int j = 0; j < listaAsignaturasRequeridas.size(); j++) {
                    int contador = 0;

                    Asignatura asignaturaRequerida = listaAsignaturasRequeridas.get(j);
                    int claveAsignaturaRequerida = asignaturaRequerida.getClave_asignatura();

                    for (int k = 0; k < listaDeTodasLasAsignaturasAprobadas.size(); k++) {
                        AsignaturaOfertaAcademica asignaturaAprobada = listaDeTodasLasAsignaturasAprobadas.get(k);
                        int claveAsignaturaAprobada = asignaturaAprobada.getClaveAsignatura();

                        if (claveAsignaturaAprobada == claveAsignaturaRequerida) {
                            contador++;
                        }
                    }

                    if (contador == 0) {
                        asignaturaDependiente.restarPonderacion(3);
                    }
                }
            }
        }

    }

    private ArrayList<AsignaturaOfertaAcademicaPonderada> unirArreglosDeAsignaturasPonderadas(ArrayList<AsignaturaOfertaAcademicaPonderada> listaAsignaturasPonderadasNormalesRecursables, ArrayList<AsignaturaOfertaAcademicaPonderada> listaAsignaturasPonderadasNormalesCursablesSinRecursables, ArrayList<AsignaturaOfertaAcademicaPonderada> listaAsignaturasPonderadasOptativasRecursables, ArrayList<AsignaturaOfertaAcademicaPonderada> listaAsignaturasPonderadasOptativasCursablesSinRecursables) {
        ArrayList<AsignaturaOfertaAcademicaPonderada> arregloAsignaturasOrdenadas = new ArrayList<AsignaturaOfertaAcademicaPonderada>();

        arregloAsignaturasOrdenadas.addAll(listaAsignaturasPonderadasNormalesRecursables);
        arregloAsignaturasOrdenadas.addAll(listaAsignaturasPonderadasNormalesCursablesSinRecursables);
        arregloAsignaturasOrdenadas.addAll(listaAsignaturasPonderadasOptativasRecursables);
        arregloAsignaturasOrdenadas.addAll(listaAsignaturasPonderadasOptativasCursablesSinRecursables);

        return arregloAsignaturasOrdenadas;
    }

    private ArrayList<AsignaturaOfertaAcademicaPonderada> unirArreglosDeAsignaturasPonderadas(ArrayList<AsignaturaOfertaAcademicaPonderada> listaAsignaturasPonderadasNormalesRecursables, ArrayList<AsignaturaOfertaAcademicaPonderada> listaAsignaturasPonderadasNormalesCursablesSinRecursables) {
        ArrayList<AsignaturaOfertaAcademicaPonderada> arregloAsignaturasOrdenadas = new ArrayList<AsignaturaOfertaAcademicaPonderada>();

        arregloAsignaturasOrdenadas.addAll(listaAsignaturasPonderadasNormalesRecursables);
        arregloAsignaturasOrdenadas.addAll(listaAsignaturasPonderadasNormalesCursablesSinRecursables);

        return arregloAsignaturasOrdenadas;
    }

    private ArrayList<OpcionHorario> obtenerOpcionesDeHorario(ArrayList<AsignaturaOfertaAcademicaPonderada> listaAsignaturasOrdenadas, int numeroAsignaturasAGenerar) {
        System.out.println("Generando combinaciones de horarios");
        ArrayList<OpcionHorario> opcionesDeHorario = obtenerCombinacionesDeOpcionesDeHorario(listaAsignaturasOrdenadas, numeroAsignaturasAGenerar);
        System.out.println("Ordenando opciones de horarios");
        ordenarPorPonderacionOpcionesDeHorario(opcionesDeHorario);

        return opcionesDeHorario;
    }

    private ArrayList<OpcionHorario> obtenerCombinacionesDeOpcionesDeHorario(ArrayList<AsignaturaOfertaAcademicaPonderada> listaAsignaturasOrdenadas, int numeroAsignaturasAGenerar) {

        Iterador iteradorCombinacion = new Iterador(listaAsignaturasOrdenadas, numeroAsignaturasAGenerar);
        Iterator iterador = iteradorCombinacion.iterator();

        System.out.println("Iniciado " + new java.util.Date().toLocaleString());

        ArrayList<OpcionHorario> opcionesDeHorario = new ArrayList<OpcionHorario>();

        while (iterador.hasNext()) {
            boolean seAgregara = true;
            OpcionHorario opcionHorario = (OpcionHorario) iterador.next();
         
            if(opcionHorario.getListaAsignaturas().size() == numeroAsignaturasAGenerar) {
                
                if(!existeLaMismaAsignaturaEnLaOpcionDeHorario(opcionHorario)) {

                ArrayList<AsignaturaOfertaAcademicaPonderada> listaAsignaturas = opcionHorario.getListaAsignaturas();

                    for (int i = 0; i < listaAsignaturas.size(); i++) {
                        AsignaturaOfertaAcademicaPonderada asignatura1 = listaAsignaturas.get(i);

                        int j = i + 1;

                        if (j < listaAsignaturas.size()) {
                            for (; j < listaAsignaturas.size(); j++) {
                                AsignaturaOfertaAcademicaPonderada asignatura2 = listaAsignaturas.get(j);

                                if (colisionanLasAsignaturas(asignatura1, asignatura2)) {
                                    seAgregara = false;
                                    break;
                                }
                            }
                        }               
                    }
                    if (seAgregara == true) {
                        opcionesDeHorario.add(opcionHorario);
                    }
                }
            }         
        }

        System.out.println("FInalizado " + new java.util.Date().toLocaleString());

        return opcionesDeHorario;

    }
    
    private void ordenarPorPonderacionOpcionesDeHorario (ArrayList<OpcionHorario> opcionesDeHorario) {
        Collections.sort(opcionesDeHorario, Collections.reverseOrder(new ComparadorPonderacion()));                 
    }
    
    private boolean existeLaMismaAsignaturaEnLaOpcionDeHorario(OpcionHorario opcionHorario) {
        
        ArrayList<AsignaturaOfertaAcademicaPonderada> listaAsignaturas = opcionHorario.getListaAsignaturas();
        
        for(int i = 0; i < listaAsignaturas.size(); i++) {
            
            int j = i + 1;

            if (j < listaAsignaturas.size()) {
                for (; j < listaAsignaturas.size(); j++) {
                    int claveAsignatura1 = listaAsignaturas.get(i).getAsignaturaOferta().getClaveAsignatura();
                    int claveAsignatura2 = listaAsignaturas.get(j).getAsignaturaOferta().getClaveAsignatura();
                    
                    if(claveAsignatura1 == claveAsignatura2) {
                        return true;
                    }
                }
            }
        }
        
        return false;
        
    }

    private boolean colisionanLasAsignaturas(AsignaturaOfertaAcademicaPonderada asignatura1, AsignaturaOfertaAcademicaPonderada asignatura2) {

        ArrayList<FragmentoHorario> listaHorariosAsignatura1 = asignatura1.getAsignaturaOferta().getHorario();
        ArrayList<FragmentoHorario> listaHorariosAsignatura2 = asignatura2.getAsignaturaOferta().getHorario();

        for (int i = 0; i < listaHorariosAsignatura1.size(); i++) {
            FragmentoHorario horarioAsignatura1 = listaHorariosAsignatura1.get(i);

            for (int k = 0; k < listaHorariosAsignatura2.size(); k++) {
                FragmentoHorario horarioAsignatura2 = listaHorariosAsignatura2.get(k);

                if (colisionanLosHorarios(horarioAsignatura1, horarioAsignatura2)) {
                    return true;
                }
            }
        }

        return false;
    }

    private boolean colisionanLosHorarios(FragmentoHorario horarioAsignatura1, FragmentoHorario horarioAsignatura2) {

        String diaAsignatura1 = horarioAsignatura1.getDiaSemana();
        String diaAsignatura2 = horarioAsignatura2.getDiaSemana();

        if (diaAsignatura1.equals(diaAsignatura2)) {

            String horaInicioAsignatura1 = horarioAsignatura1.getHoraInicio();
            String horaFinAsignatura1 = horarioAsignatura1.getHoraFin();
            String horaInicioAsignatura2 = horarioAsignatura2.getHoraInicio();
            String horaFinAsignatura2 = horarioAsignatura2.getHoraFin();

            if (horaInicioAsignatura1.compareTo(horaInicioAsignatura2) == 0) {
                return true;
            } else if (horaInicioAsignatura1.compareTo(horaInicioAsignatura2) > 0) {

                if (horaInicioAsignatura1.compareTo(horaFinAsignatura2) == 0) {
                    return false;
                } else if (horaInicioAsignatura1.compareTo(horaFinAsignatura2) > 0) {
                    return false;
                } else {
                    return true;
                }

            } else {
                if (horaFinAsignatura1.compareTo(horaInicioAsignatura2) == 0) {
                    return false;
                } else if (horaFinAsignatura1.compareTo(horaInicioAsignatura2) > 0) {
                    return true;
                } else {
                    return false;
                }
            }
        } else {
            return false;
        }
    }

    //Optativas
    private int obtenerClaveAreaDeConcentracionDeAsignaturaOptativa(AsignaturaOfertaAcademica asignaturaOptativa) {

        int claveAsignatura = asignaturaOptativa.getClaveAsignatura();

        DAOAsignaturaOptativa daoAsignaturaOptativa = new DAOAsignaturaOptativa();
        int claveAreaConcentracion = daoAsignaturaOptativa.obtenerClaveAreaDeConcentracionDeLaAsignatura(claveAsignatura);
        daoAsignaturaOptativa.cerrarConexionAAsignaturaOptativa();

        return claveAreaConcentracion;
    }

    private int obtenerNumeroDeAsignaturasOptativasAprobadas(ArrayList<AsignaturaOfertaAcademica> listaAsignaturasOptativasAprobadas) {
        return listaAsignaturasOptativasAprobadas.size();
    }

    private int obtenerNumeroDeAsignaturasAprobadasPorAreaDeConcentracion(ArrayList<AsignaturaOfertaAcademica> listaAsignaturasOptativasAprobadas, int claveAreaConcentracion) {
        int asignaturasAprobadasPorAreaConcentracion = 0;

        for (int i = 0; i < listaAsignaturasOptativasAprobadas.size(); i++) {
            AsignaturaOfertaAcademica asignaturaOptativa = listaAsignaturasOptativasAprobadas.get(i);

            int claveAreaConcentracionDeAsignatura = obtenerClaveAreaDeConcentracionDeAsignaturaOptativa(asignaturaOptativa);

            if (claveAreaConcentracionDeAsignatura == claveAreaConcentracion) {
                asignaturasAprobadasPorAreaConcentracion++;
            }
        }

        return asignaturasAprobadasPorAreaConcentracion;
    }
    
    private void imprimirOpcionesDeHorario(ArrayList<OpcionHorario> opcionesDeHorario, PrintWriter out) {
        
        String respuesta = "<h1>OPCIONES DE HORARIO GENERADAS</h1><br/>";
                
        for(int i = 0; i < opcionesDeHorario.size(); i++) {
            respuesta += "Opcion de horario "+ (i+1) + "<br/>";
            OpcionHorario opcionDeHorario = opcionesDeHorario.get(i);

            respuesta += imprimirOpcionDeHorario(opcionDeHorario);
            
            respuesta += "<br/>";
            respuesta += "<br/>";
        }
        
        if(opcionesDeHorario.isEmpty()) {
            out.println("<h1>OPCIONES DE HORARIO GENERADAS</h1><br/>No existen opciones de horario para tu configuración.");
        }
        else {
            out.println(respuesta);
        }
    }
  
    private String imprimirOpcionDeHorario(OpcionHorario opcionHorario){
                        
        ArrayList<AsignaturaOfertaAcademicaPonderada> listaAsignaturas = opcionHorario.getListaAsignaturas();
        
        String respuesta = 
                "<table border=\"1\">"
               +"   <th>"
               +"       Asignatura"
               +"   </th>"
               +"   <th>"
               +"       Profesor"
               +"   </th>"
               +"   <th>"
               +"       Lunes"
               +"   </th>"
               +"   <th>"
               +"       Martes"
               +"   </th>"
               +"   <th>"
               +"       Mi&eacute;rcoles"
               +"   </th>"
               +"   <th>"
               +"       Jueves"
               +"   </th>"
               +"   <th>"
               +"       Viernes"
               +"   </th>";
        for(int i = 0; i < listaAsignaturas.size(); i++) {
            AsignaturaOfertaAcademicaPonderada asignatura = listaAsignaturas.get(i);            
            
            respuesta += 
                    "   <tr>"
                   +"       <td>"
                   +"           "+asignatura.getAsignaturaOferta().getNombre()
                   +"       </td>"                   
                   +"       <td>"
                   +"           "+asignatura.getAsignaturaOferta().getMaestro().getNombre()+" "+asignatura.getAsignaturaOferta().getMaestro().getApellido()
                   +"       </td>" 
                    ;
            
            ArrayList<FragmentoHorario> listaHorarios = asignatura.getAsignaturaOferta().getHorario(); 
            
            int contadorLunes = 0;
            for(int j = 0; j < listaHorarios.size() ; j++) {
                FragmentoHorario fragmentoHorario = listaHorarios.get(j);
                
                if(fragmentoHorario.getDiaSemana().equalsIgnoreCase(LUNES)) {
                    respuesta +=
                             "       <td>"
                            +"           Hora: "+fragmentoHorario.getHoraInicio()+" - "+fragmentoHorario.getHoraFin()+"<br/>"
                            +"           Aula: "+fragmentoHorario.getAula()
                            +"       </td>";
                    contadorLunes++;
                }               
            }  
            
            if(contadorLunes == 0) {
                {
                    respuesta +=
                            "       <td>"                          
                           +"       </td>"; 
                }
            }
            
            int contadorMartes = 0;
            for(int j = 0; j < listaHorarios.size() ; j++) {
                FragmentoHorario fragmentoHorario = listaHorarios.get(j);
                
                if(fragmentoHorario.getDiaSemana().equalsIgnoreCase(MARTES)) {
                    respuesta +=
                             "       <td>"
                            +"           Hora: "+fragmentoHorario.getHoraInicio()+" - "+fragmentoHorario.getHoraFin()+"<br/>"
                            +"           Aula: "+fragmentoHorario.getAula()
                            +"       </td>";
                    contadorMartes++;
                }
            }    
            
            if(contadorMartes == 0) {
                {
                    respuesta +=
                            "       <td>"                          
                           +"       </td>"; 
                }
            }
            
            int contadorMiercoles = 0;
            for(int j = 0; j < listaHorarios.size() ; j++) {
                FragmentoHorario fragmentoHorario = listaHorarios.get(j);
                
                if(fragmentoHorario.getDiaSemana().equalsIgnoreCase(MIERCOLES)) {
                    respuesta +=
                             "       <td>"
                            +"           Hora: "+fragmentoHorario.getHoraInicio()+" - "+fragmentoHorario.getHoraFin()+"<br/>"
                            +"           Aula: "+fragmentoHorario.getAula()
                            +"       </td>";
                    contadorMiercoles++;
                }
            }     
            
            if(contadorMiercoles == 0) {
                {
                    respuesta +=
                            "       <td>"                          
                           +"       </td>"; 
                }
            }
            
            int contadorJueves = 0;
            for(int j = 0; j < listaHorarios.size() ; j++) {
                FragmentoHorario fragmentoHorario = listaHorarios.get(j);
                
                if(fragmentoHorario.getDiaSemana().equalsIgnoreCase(JUEVES)) {
                    respuesta +=
                             "       <td>"
                            +"           Hora: "+fragmentoHorario.getHoraInicio()+" - "+fragmentoHorario.getHoraFin()+"<br/>"
                            +"           Aula: "+fragmentoHorario.getAula()
                            +"       </td>";
                    contadorJueves++;
                }
            }      
            
            if(contadorJueves == 0) {
                {
                    respuesta +=
                            "       <td>"                          
                           +"       </td>"; 
                }
            }
            
            int contadorViernes = 0;
            for(int j = 0; j < listaHorarios.size() ; j++) {
                FragmentoHorario fragmentoHorario = listaHorarios.get(j);
                
                if(fragmentoHorario.getDiaSemana().equalsIgnoreCase(VIERNES)) {
                    respuesta +=
                             "       <td>"
                            +"           Hora: "+fragmentoHorario.getHoraInicio()+" - "+fragmentoHorario.getHoraFin()+"<br/>"
                            +"           Aula: "+fragmentoHorario.getAula()
                            +"       </td>";
                    contadorViernes++;
                }
            }     
            
            if(contadorViernes == 0) {
                {
                    respuesta +=
                            "       <td>"                          
                           +"       </td>"; 
                }
            }
            
            respuesta += "</tr>";
        }
        respuesta += "</table>";
        
        return respuesta;
    }
    
    private final int ESTADO_CURSABLE_SIN_RECURSABLE = -1;
    private final int ESTADO_APROBADA = 0;//Asignatura que el alumno ya curso y Aprovo
    private final int ESTADO_RECURSABLE = 1;//Asignatura que el alumno ya curso y reprovo 
    private final int ESTADO_NO_CURSABLE = 2;//Asignatura que el alumno ya recurso y reprovo
    private final int PONDERACION_ASIGNATURA_RECURSABLE = 15;
    private final int PONDERACION_ASIGNATURA_NORMAL = 5;
    private final int PONDERACION_ASIGNATURA_OPTATIVA = 2;     
    private final String LUNES = "LUNES";
    private final String MARTES = "MARTES";
    private final String MIERCOLES = "MIÉRCOLES";
    private final String JUEVES = "JUEVES";
    private final String VIERNES = "VIERNES";       
}
